package com.cmes.web.json;

import com.cmes.core.json.CachedFormatSerializer;
import com.cmes.core.utils.DateHelper;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.std.NumberSerializer;
import com.fasterxml.jackson.databind.ser.std.NumberSerializers;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.context.annotation.Bean;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Locale;
import java.util.TimeZone;

/**
 * Jackson 自动配置
 *
 * @author Bruce.Gong
 * @since 1.0.0-SNAPSHOT
 */
@Slf4j
@ConditionalOnClass(ObjectMapper.class)
@AutoConfigureBefore(JacksonAutoConfiguration.class)
public class JsonAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public Jackson2ObjectMapperBuilderCustomizer customizer() {
        return builder -> {
            // 时区
            builder.locale(Locale.CHINA);
            builder.timeZone(TimeZone.getTimeZone("GMT+8"));

            // 日期格式化
            builder.serializerByType(LocalDateTime.class, new LocalDateTimeSerializer(DateHelper.DATE_TIME_FORMATTER));
            builder.serializerByType(LocalDate.class, new LocalDateSerializer(DateHelper.DATE_FORMATTER));
            builder.serializerByType(LocalTime.class, new LocalTimeSerializer(DateHelper.TIME_FORMATTER));
            builder.deserializerByType(LocalDateTime.class, new LocalDateTimeDeserializer(DateHelper.DATE_TIME_FORMATTER));
            builder.deserializerByType(LocalDate.class, new LocalDateDeserializer(DateHelper.DATE_FORMATTER));
            builder.deserializerByType(LocalTime.class, new LocalTimeDeserializer(DateHelper.TIME_FORMATTER));

            // 数字格式化
            builder.serializerByType(BigDecimal.class, new CachedFormatSerializer<>(BigDecimal.class, new NumberSerializer(BigDecimal.class)));
            builder.serializerByType(Double.class, new CachedFormatSerializer<>(Double.class, new NumberSerializers.DoubleSerializer(Double.class)));
            builder.serializerByType(Double.TYPE, new CachedFormatSerializer<>(Double.TYPE, new NumberSerializers.DoubleSerializer(Double.TYPE)));
            builder.serializerByType(Integer.class, new CachedFormatSerializer<>(Integer.class, new NumberSerializers.IntegerSerializer(Integer.class)));
            builder.serializerByType(Integer.TYPE, new CachedFormatSerializer<>(Integer.TYPE, new NumberSerializers.IntegerSerializer(Integer.TYPE)));
            builder.serializerByType(Long.class, new CachedFormatSerializer<>(Long.class, ToStringSerializer.instance));
            builder.serializerByType(Long.TYPE, new CachedFormatSerializer<>(Long.TYPE, ToStringSerializer.instance));

            // 属性
            builder.featuresToEnable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
            builder.featuresToDisable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        };
    }

}
